package com.cqrt.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import com.hustcad.plm.pdm.core.handle.exception.SystemErrorCodeEnum;
import com.hustcad.plm.pdm.core.util.Tools;
import com.hustcad.plm.rpm.changeevent.DataChangeSendMessageEvent;
import com.hustcad.plm.rpm.entityconvert.BaseConvert;
import com.hustcad.plm.rpm.entityconvert.admin.ProjectConvert;
import com.hustcad.plm.rpm.model.converters.PlanConverter;
import com.hustcad.plm.rpm.model.entity.admin.TyppmProject;
import com.hustcad.plm.rpm.model.entity.job.TyppmJob;
import com.hustcad.plm.rpm.model.entity.plan.TyppmPlan;
import com.hustcad.plm.rpm.model.qc.OperationRecordQC;
import com.hustcad.plm.rpm.model.vo.access.TyppmOperationControlRuleVO;
import com.hustcad.plm.rpm.project.service.impl.TyppmProjectServiceImpl;
import com.hustcad.plm.rpm.service.access.TyppmOperationControlRuleService;
import com.hustcad.plm.rpm.service.job.TyppmJobService;
import com.hustcad.plm.rpm.service.operationrecord.TyppmOperationRecordService;
import com.hustcad.plm.rpm.service.plan.TyppmPlanActiveService;
import com.hustcad.plm.rpm.service.plan.TyppmPlanService;
import com.hustcad.plm.rpm.serviceextend.ProjectStateExtendService;
import com.ty.ppm.api.service.admin.ProjectService;
import com.ty.ppm.api.service.plan.PlanService;
import com.ty.ppm.model.dto.admin.ProjectDTO;
import com.ty.ppm.model.entity.admin.Project;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Primary
@Slf4j
public class RTTyppmProjectServiceImpl extends TyppmProjectServiceImpl {
    @Resource
    private TyppmPlanService typpmPlanService;
    @Resource
    private TyppmPlanActiveService typpmPlanActiveService;
    @Resource
    private TyppmJobService typpmJobService;
    @Resource
    private ProjectConvert projectConvert;
    @Resource
    private BaseConvert baseConvert;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @Resource
    private ProjectService projectService;
    @Resource
    private PlanService planService;
    @Resource
    private ProjectStateExtendService projectStateExtendService;
    @Resource
    private PlanConverter planConverter;
    @Resource
    private TyppmOperationRecordService typpmOperationRecordService;
    @Resource
    private TyppmOperationControlRuleService typpmOperationControlRuleService;

    @Transactional(
            rollbackFor = {Exception.class}
    )
    @GlobalTransactional
    public void setProjectStatePaused(List<String> list) {

        for (String oid : list) {
            TyppmProject typpmProject = this.selectOneByOID(oid);
            if ("ty.inteplm.project.CTyProject".equals(typpmProject.getOtype())) {
                this.checkOperationControlRule(typpmProject, "暂停");
            }

            typpmProject.setPrevCompletionStatus(typpmProject.getCompletionStatus());
            typpmProject.setCompletionStatus(3);
            TyppmPlan plan = this.typpmPlanService.queryPlanByParent(typpmProject.getOid(), typpmProject.getOtype());
            if (Objects.isNull(plan)) {
                throw SystemErrorCodeEnum.ENTITY_NONE.message(new Object[]{"项目计划"});
            }

            //            Boolean locked = plan.isLocked();
            //            if (Boolean.TRUE.equals(locked)) {
            //                throw SystemErrorCodeEnum.OBJECT_HAVE_LOCKED_BY_USER.message(new Object[]{"项目计划[" + plan.getName() + "]", plan.getLockUserName()});
            //            }

            //            this.typpmPlanActiveService.checkAllActiveIsLocked(plan.getOid(), plan.getOtype(), (TyppmUser)null);
            this.projectService.updateProjectByOid(
                    this.transformProjectForSpecialField(typpmProject, ProjectDTO.class));
            this.typpmPlanActiveService.batchSetActiveStatePausedByPlan(plan.getOid());
            List<String> notSatList = Arrays.asList("已完成", "已终止");
            Map<String, Object> params = new HashMap();
            params.put("projectID", typpmProject.getOid());
            params.put("notStateList", notSatList);
            params.put("markfordelete", 0L);
            List<TyppmJob> jobList = this.typpmJobService.queryJobListByParams(params);
            this.typpmJobService.batchSetJobStatePaused(params);
            this.jobStatePausedSendMessage(jobList, "已暂停", "已暂停");
            this.insertOperationRecord(oid);
            DataChangeSendMessageEvent dataChangeSendMessageEvent = new DataChangeSendMessageEvent(typpmProject, "",
                                                                                                   "");
            this.applicationEventPublisher.publishEvent(dataChangeSendMessageEvent);
        }

    }

    private void insertOperationRecord(String oid) {
        OperationRecordQC setProjectStatePausedQc = new OperationRecordQC();
        setProjectStatePausedQc.setLinkOID(oid);
        setProjectStatePausedQc.setLinkOTYPE("ty.inteplm.project.CTyProject");
        setProjectStatePausedQc.setRefOID(oid);
        setProjectStatePausedQc.setRefOTYPE("ty.inteplm.project.CTyProject");
        setProjectStatePausedQc.setRefName("当前项目");
        setProjectStatePausedQc.setPassName("调整");
        setProjectStatePausedQc.setRecordTYPE("项目-编辑");
        setProjectStatePausedQc.setAfterValue("【暂停】");
        setProjectStatePausedQc.setBeforeValue("");
        setProjectStatePausedQc.setRemark("状态为");
        this.typpmOperationRecordService.insertOperationRecordForRPM(setProjectStatePausedQc);
    }

    private void jobStatePausedSendMessage(List<TyppmJob> jobList, String oldState, String curState) {
        List<String> notSatList = Arrays.asList("已终止", "已完成");
        if (CollUtil.isNotEmpty(jobList)) {
            jobList.stream().filter((job) -> !notSatList.contains(job.getState())).forEach((job) -> {
                DataChangeSendMessageEvent dataChangeSendMessageEvent = new DataChangeSendMessageEvent(job, StringUtils.isNotEmpty(oldState) ? oldState : job.getState(), StringUtils.isNotEmpty(curState) ? curState : job.getState());
                this.applicationEventPublisher.publishEvent(dataChangeSendMessageEvent);
            });
        }

    }

    private <S extends TyppmProject, T extends Project> T transformProjectForSpecialField(S s, Class<T> targetType) {
        if (Objects.nonNull(s)) {
            T t = ReflectUtil.newInstanceIfPossible(targetType);
            this.baseConvert.copyProperties(s, t);
            t.setBranchidtypedefref(Tools.toBigInteger(s.getTypeBranchid()));
            t.setEntrysetadhocaclblob(s.getEntrySetBlob());
            t.setGroupoid(Tools.toBigInteger(s.getAdministratorsOID()));
            t.setGroupotype(s.getAdministratorsOTYPE());
            t.setBusinessnamespacecontainerinfo(Boolean.TRUE.equals(s.getBusinessNamespace()) ? 1L : 0L);
            t.setContainerdomainoid(Tools.toBigInteger(s.getParentDomainOID()));
            t.setContainerdomainotype(s.getParentDomainOTYPE());
            t.setSystemdomainrefisnullcontain(Boolean.TRUE.equals(s.getSystemDomainrefIsNull()) ? 1L : 0L);
            t.setPrivateaccesscontainerinfo(Boolean.TRUE.equals(s.getPrivateAccess()) ? 1L : 0L);
            t.setTypeadministrativelock(s.getAdministrativeLock());
            t.setStatecontainerteammanagedin(s.getContainerTreamMngState());
            t.setSendinvitationscontainerteam(Boolean.TRUE.equals(s.getSendInvitations()) ? 1L : 0L);
            t.setAllowusertoconfigureaccessco(Boolean.TRUE.equals(s.getAllowUserToConfigureAccess()) ? 1L : 0L);
            t.setActiveflagcontainerteammanag(Boolean.TRUE.equals(s.getActiveFlag()) ? 1L : 0L);
            t.setContainerteamidisnullcontain(Boolean.TRUE.equals(s.getContainerTeamIsNull()) ? 1L : 0L);
            t.setSharedteamidisnullcontainer(Boolean.TRUE.equals(s.getSharedTeamIsNull()) ? 1L : 0L);
            t.setExtendablecontainerteammanag(Boolean.TRUE.equals(s.getExtendable()) ? 1L : 0L);
            return t;
        } else {
            return null;
        }
    }

    private void checkOperationControlRule(TyppmProject typpmProject, String operation) {
        TyppmOperationControlRuleVO typpmOperationControlRuleVO = new TyppmOperationControlRuleVO();
        typpmOperationControlRuleVO.setMasterType("项目");
        typpmOperationControlRuleVO.setObjOid(typpmProject.getOid());
        typpmOperationControlRuleVO.setObjOtype(typpmProject.getOtype());
        String operationControlRule = this.typpmOperationControlRuleService.getOperationControlRule(typpmOperationControlRuleVO);
        List<String> operationControlRuleList = Stream.of(operationControlRule.split(";")).collect(Collectors.toList());
        int completionStatus = typpmProject.getCompletionStatus();
        String projectName = typpmProject.getName();
        if (!operationControlRuleList.contains(operation)) {
            switch (completionStatus) {
                case 0:
                    throw SystemErrorCodeEnum.PROJECT_STATE_NOT_STARTED.message(projectName);
                case 1:
                    throw SystemErrorCodeEnum.PROJECT_STATE_IMPLEMENTATION.message(projectName);
                case 2:
                    throw SystemErrorCodeEnum.PROJECT_STATE_COMPLETED.message(projectName);
                case 3:
                    throw SystemErrorCodeEnum.PROJECT_STATE_PAUSED.message(projectName);
                case 4:
                    throw SystemErrorCodeEnum.PROJECT_STATE_TERMINATION.message(projectName);
            }
        }

    }

    @Transactional(
            rollbackFor = {Exception.class}
    )
    public void setProjectStateRecovery(List<String> list) {
        Boolean returnFlag = this.projectStateExtendService.projectStateRecoveryBefore(list);
        if (!Boolean.TRUE.equals(returnFlag)) {

            for (String oid : list) {
                TyppmProject typpmProject = this.selectOneByOID(oid);
                if ("ty.inteplm.project.CTyProject".equals(typpmProject.getOtype())) {
                    this.checkOperationControlRule(typpmProject, "恢复启动");
                }

                this.setProjectState(typpmProject);
                this.insertRecordForStateStarted(oid);
                this.setPlanState(typpmProject);
            }

            this.projectStateExtendService.projectStateRecoveryAfter(list);
        }
    }

    private void setProjectState(TyppmProject typpmProject) {
        if (Integer.valueOf(3).equals(typpmProject.getCompletionStatus())) {
            typpmProject.setPrevCompletionStatus(typpmProject.getCompletionStatus());
            TyppmPlan plan = this.typpmPlanService.queryPlanByParent(typpmProject.getOid(), typpmProject.getOtype());
            if (plan != null) {
                this.typpmPlanActiveService.batchSetActiveStateRecoveryByPlan(plan.getOid());
            }

            List<String> notSatList = Arrays.asList("已完成", "已终止");
            Map<String, Object> params = new HashMap();
            params.put("projectID", typpmProject.getOid());
            params.put("notStateList", notSatList);
            params.put("markfordelete", 0L);
            List<TyppmJob> jobList = this.typpmJobService.queryJobListByParams(params);
            this.typpmJobService.batchSetJobStateRecovery(params);
            this.jobStatePausedSendMessage(jobList);
        }

    }

    private void jobStatePausedSendMessage(List<TyppmJob> jobList) {
        this.jobStatePausedSendMessage(jobList, null, null);
    }

    private void insertRecordForStateStarted(String oid) {
        OperationRecordQC setProjectStateStartedQc = new OperationRecordQC();
        setProjectStateStartedQc.setLinkOID(oid);
        setProjectStateStartedQc.setLinkOTYPE("ty.inteplm.project.CTyProject");
        setProjectStateStartedQc.setRefOTYPE("ty.inteplm.project.CTyProject");
        setProjectStateStartedQc.setRefOID(oid);
        setProjectStateStartedQc.setRefName("当前项目");
        setProjectStateStartedQc.setPassName("调整");
        setProjectStateStartedQc.setRecordTYPE("项目-编辑");
        setProjectStateStartedQc.setAfterValue("【启动】");
        setProjectStateStartedQc.setBeforeValue("");
        setProjectStateStartedQc.setRemark("状态为");
        this.typpmOperationRecordService.insertOperationRecordForRPM(setProjectStateStartedQc);
    }

    private void setPlanState(TyppmProject typpmProject) {
        TyppmPlan plan = this.typpmPlanService.queryPlanByParent(typpmProject.getOid(), typpmProject.getOtype());
        plan.setActualStartDate(LocalDateTime.now());
        this.planService.updatePlanTransactional(this.planConverter.fromRemote(plan));
        typpmProject.setCompletionStatus(1);
        this.projectService.updateProjectByOid(this.projectConvert.trans(typpmProject));
        DataChangeSendMessageEvent dataChangeSendMessageEvent = new DataChangeSendMessageEvent(typpmProject, "", "");
        this.applicationEventPublisher.publishEvent(dataChangeSendMessageEvent);
    }
}
